package com.luqili.utils.pub.number;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;

import java.math.BigDecimal;
import java.util.Stack;

public class NumberUtilsExt {

    /**
     * 该字典表不可随意修改
     * <li>考虑web页面使用，排除转义字符<>'\"|
     */
    private static char[] CHAR_DIC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz[]{}()=#$%&*+,.!?:;^~_`/".toCharArray();

    /**
     * Long 转换为Byte数组
     *
     * @param x
     * @return
     */
    public static byte[] long2Bytes(long x) {
        byte[] bb = new byte[8];
        bb[0] = (byte) (x >> 56);
        bb[1] = (byte) (x >> 48);
        bb[2] = (byte) (x >> 40);
        bb[3] = (byte) (x >> 32);
        bb[4] = (byte) (x >> 24);
        bb[5] = (byte) (x >> 16);
        bb[6] = (byte) (x >> 8);
        bb[7] = (byte) (x >> 0);
        return bb;
    }

    /**
     * byte[8] 数组转换为Long
     *
     * @param bb
     * @return
     */
    public static long bytes2Long(byte[] bb) {
        return ((((long) bb[0] & 0xff) << 56) | (((long) bb[1] & 0xff) << 48) | (((long) bb[2] & 0xff) << 40) | (((long) bb[3] & 0xff) << 32) | (((long) bb[4] & 0xff) << 24)
            | (((long) bb[5] & 0xff) << 16) | (((long) bb[6] & 0xff) << 8) | (((long) bb[7] & 0xff) << 0));
    }

    public static byte[] int2Bytes(int i) {
        byte[] result = new byte[4];
        result[0] = (byte) ((i >> 24) & 0xFF);
        result[1] = (byte) ((i >> 16) & 0xFF);
        result[2] = (byte) ((i >> 8) & 0xFF);
        result[3] = (byte) (i & 0xFF);
        return result;
    }

    public static int bytes2Int(byte[] bb) {
        return (((int) bb[0] & 0xff) << 24) | (((int) bb[1] & 0xff) << 16) | (((int) bb[2] & 0xff) << 8) | (((int) bb[3] & 0xff) << 0);
    }

    /**
     * Short 转 byte[]
     *
     * @param i
     * @return
     */
    public static byte[] short2Bytes(short i) {
        byte[] result = new byte[2];
        result[0] = (byte) ((i >> 8) & 0xFF);
        result[1] = (byte) (i & 0xFF);
        return result;
    }

    /**
     * Byte[] 转 Short
     *
     * @param bb
     * @return
     */
    public static short bytes2Short(byte[] bb) {
        return (short) ((((short) bb[0] & 0xff) << 8) | (((short) bb[1] & 0xff) << 0));
    }

    /**
     * 转数组
     *
     * @param b
     * @return
     */
    public static byte[] byte2Bytes(byte... b) {
        return b;
    }

    /**
     * 10进制转N进制
     *
     * @param number
     * @param length
     * @param n      进制位数
     * @return
     * @author luqili
     * @version 2018年8月21日
     */
    public static String number10ToN(long number, long length, int n) {
        if (n < 2 || n > CHAR_DIC.length) {
            throw new RuntimeException("进制位数错误,限制为2~" + CHAR_DIC.length);
        }
        Long rest = number;
        Stack<Character> stack = new Stack<Character>();
        StringBuilder result = new StringBuilder(0);
        if (rest < 0) {// 负数
            result.append("-");
            rest = Math.abs(rest);
        }
        while (rest != 0) {
            stack.add(CHAR_DIC[(int) Math.abs(rest - (rest / n) * n)]);
            rest = rest / n;
        }
        for (; !stack.isEmpty(); ) {
            result.append(stack.pop());
        }
        int result_length = result.length();
        StringBuilder temp0 = new StringBuilder();
        for (int i = 0; i < length - result_length; i++) {
            temp0.append('0');
        }

        return temp0.toString() + result.toString();
    }

    /**
     * N进制转10进制 可能会数值溢出
     *
     * @param digit
     * @param n
     * @return
     * @author luqili
     * @version 2018年8月21日
     */
    public static long numberNTo10(String digit, int n) {
        long dst = 0L;
        boolean isPlus = true;
        if (digit.startsWith("-")) {
            StringUtils.removeStart(digit, "-");
            isPlus = false;
        }
        for (int i = 0; i < digit.length(); i++) {
            char c = digit.charAt(i);
            for (int j = 0; j < CHAR_DIC.length; j++) {
                if (c == CHAR_DIC[j]) {
                    long sum = dst;
                    if (isPlus) {
                        dst = (dst * n) + j;
                        if (sum > dst) {
                            throw new RuntimeException("数值溢出1");
                        }
                    } else {
                        dst = (dst * n) - j;
                        if (sum < dst) {
                            throw new RuntimeException("数值溢出2");
                        }
                    }
                    break;
                }
            }
        }
        return dst;
    }

    /**
     * 10进制转62进制
     *
     * @param number
     * @return
     * @author luqili
     * @version 2018年8月21日
     */
    public static String number10To62(long number) {
        return number10ToN(number, 1, 62);
    }

    /**
     * 62进制转10进制
     *
     * @param digit
     * @return
     * @author luqili
     * @version 2018年8月21日
     */
    public static long number62To10(String digit) {
        return numberNTo10(digit, 62);
    }

    /**
     * 10进制转91进制 废弃算法
     *
     * @param number
     * @return
     * @author luqili
     * @version 2018年8月21日
     */
    @Deprecated
    public static String number10To86(long number) {
        return number10ToN(number, 1, 86);
    }

    /**
     * 91进制转10进制
     *
     * @param digit
     * @return
     * @author luqili
     * @version 2018年8月21日
     */
    public static long number86To10(String digit) {
        return numberNTo10(digit, 86);
    }

    /**
     * 获得编号的校验码
     *
     * @param number
     * @return
     * @author luqili
     * @version 2018年8月22日
     */
    public static String numberValidCode(String number) {
        if (StringUtils.isBlank(number)) {
            return "";
        }
        char[] cs = number.toCharArray();
        int sum = 0;
        for (int i = 0; i < cs.length; i++) {
            char v1 = cs[i];
            int x2 = 0;
            for (int j = 0; j < CHAR_DIC.length; j++) {
                if (v1 == CHAR_DIC[j]) {
                    x2 = j;
                    break;
                }
            }
            sum += x2 * (i + 1) * 10;
        }
        Character r = CHAR_DIC[sum % CHAR_DIC.length];

        return r.toString();

    }

    /**
     * 格式化为Integer
     *
     * @param obj
     * @return
     */
    public static int parseInt(Object obj) {
        if (obj == null) {
            return 0;
        }
        if (obj instanceof Integer) {
            return (int) obj;
        } else if (obj instanceof Long) {
            return ((Long) obj).intValue();
        } else if (obj instanceof Byte) {
            return ((Byte) obj).intValue();
        } else if (obj instanceof Short) {
            return ((Short) obj).intValue();
        } else if (obj instanceof Double) {
            return ((Double) obj).intValue();
        } else if (obj instanceof Float) {
            return ((Float) obj).intValue();
        }
        String str = obj.toString();
        if (StringUtils.isBlank(str)) {
            return 0;
        }
        return NumberUtils.createInteger(str);
    }

    /**
     * 格式化为Long
     *
     * @param obj
     * @return
     */
    public static long parseLong(Object obj) {
        if (obj == null) {
            return 0;
        }
        if (obj instanceof Integer) {
            return ((Integer) obj).longValue();
        } else if (obj instanceof Long) {
            return ((Long) obj).longValue();
        } else if (obj instanceof Byte) {
            return ((Byte) obj).longValue();
        } else if (obj instanceof Short) {
            return ((Short) obj).longValue();
        } else if (obj instanceof Double) {
            return ((Double) obj).longValue();
        } else if (obj instanceof Float) {
            return ((Float) obj).longValue();
        }
        String str = obj.toString();
        if (StringUtils.isBlank(str)) {
            return 0;
        }
        return NumberUtils.createLong(str);
    }

    /**
     * 格式化为Double
     *
     * @param obj
     * @return
     */
    public static double parseDouble(Object obj) {
        if (obj == null) {
            return 0;
        }
        if (obj instanceof Integer) {
            return (int) obj;
        } else if (obj instanceof Long) {
            return ((Long) obj).doubleValue();
        } else if (obj instanceof Byte) {
            return ((Byte) obj).doubleValue();
        } else if (obj instanceof Short) {
            return ((Short) obj).doubleValue();
        } else if (obj instanceof Double) {
            return ((Double) obj).doubleValue();
        } else if (obj instanceof Float) {
            return ((Float) obj).doubleValue();
        }
        String str = obj.toString();
        if (StringUtils.isBlank(str)) {
            return 0.0;
        }
        return NumberUtils.createDouble(str);
    }

    /**
     * 格式化为BigDecimal
     *
     * @param obj
     * @return
     */
    public static BigDecimal parseBigDecimal(Object obj) {
        if (obj == null) {
            return BigDecimal.ZERO;
        }

        if (obj instanceof BigDecimal) {
            return (BigDecimal) obj;
        } else if (obj instanceof Long) {
            return new BigDecimal((Long) obj);
        } else if (obj instanceof Byte) {
            return new BigDecimal((Byte) obj);
        } else if (obj instanceof Short) {
            return new BigDecimal((Short) obj);
        } else if (obj instanceof Double) {
            return new BigDecimal((Double) obj);
        } else if (obj instanceof Float) {
            return new BigDecimal((Float) obj);
        }
        String str = obj.toString();
        if (StringUtils.isBlank(str)) {
            return BigDecimal.ZERO;
        }
        return NumberUtils.createBigDecimal(str);
    }

    public static void main(String[] args) {
        System.out.println(number10To86(Long.MAX_VALUE));
        System.out.println(numberValidCode("23122"));
        System.out.println(numberValidCode("3asedfx3"));
        System.out.println(numberValidCode("44"));
        System.out.println(numberValidCode("5asdc5"));
        System.out.println(numberValidCode("6a6"));
        System.out.println(numberValidCode("aasdf77"));
    }
}
